namespace Bowlus.FrontEnd
{
    using System;
    using System.Diagnostics;
    using System.Linq;

    using Bowlus.Common;
    using Bowlus.Common.Communications;
    using Bowlus.FrontEnd.RequestRouting;

    using Microsoft.Practices.Unity;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.Diagnostics;
    using Microsoft.WindowsAzure.ServiceRuntime;

    public class WebRole : RoleEntryPoint
    {
        private RoutingManager requestRoutingManager;

        private CommunicationServiceHost communicationServiceHost;

        public CommunicationServiceHost CommunicationServiceHost1
        {
            get
            {
                return this.communicationServiceHost;
            }
        }

        public override bool OnStart()
        {
            ConfigureDiagnostics();

            RoleEnvironment.Changing += RoleEnvironmentChanging;
            RoleEnvironment.Changed += this.RoleEnvironmentChanged;
            RoleEnvironment.Stopping += RoleEnvironment_Stopping;

            try
            {
                HostingInfrastructureStore.AddInstance(Settings.FrontEndRoleName, RoleEnvironment.CurrentRoleInstance.Id);

                Trace.TraceInformation("Starting front end web role.");
                var unityContainer = BowlusContainer.Current.GetInstance<IUnityContainer>();
                ContainerBootstrapper.RegisterTypes(unityContainer);
                this.requestRoutingManager = unityContainer.Resolve(typeof(RoutingManager)) as RoutingManager;

                if (this.requestRoutingManager != null)
                {
                    this.requestRoutingManager.StatusChange += this.RequestRoutingManager_StatusChange;

                    this.communicationServiceHost = new CommunicationServiceHost(this.requestRoutingManager.MessageHandler);

                    this.requestRoutingManager.Initialize();
                    Trace.TraceInformation("Started front end web role.");
                    HostingInfrastructureStore.SignalInstanceStart();
                }
                else
                {
                    Trace.Write("Cannot get an instance of RoutingManager");
                }
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.ToString());
            }

            return base.OnStart();
        }

        private static void RoleEnvironment_Stopping(object sender, RoleEnvironmentStoppingEventArgs e)
        {
            HostingInfrastructureStore.RemoveInstance();
        }

        public override void OnStop()
        {
            this.requestRoutingManager.ClearConfiguration();
            base.OnStop();
        }

        private void RoleEnvironmentChanged(object sender, RoleEnvironmentChangedEventArgs e)
        {
            if (e.Changes.Any(change => change is RoleEnvironmentTopologyChange))
            {
                HostingInfrastructureStore.WaitForAppHostToStart();

                Trace.TraceInformation("Topology change detected.");

                foreach (var topologyChange in e.Changes.OfType<RoleEnvironmentTopologyChange>())
                {
                    Trace.TraceInformation("Topology change {0}", topologyChange.RoleName);
                    this.requestRoutingManager.AppHostsChange();
                }
            }
        }

        private static void ConfigureDiagnostics()
        {
            var config = DiagnosticMonitor.GetDefaultInitialConfiguration();

            CrashDumps.EnableCollection(true);

            config.DiagnosticInfrastructureLogs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);

            // For windows azure logs
            config.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
            config.Logs.ScheduledTransferLogLevelFilter = LogLevel.Verbose;

            var cloudStorageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"));

            DiagnosticMonitor.Start(cloudStorageAccount, config);
            Trace.Listeners.Add(new DiagnosticMonitorTraceListener { Filter = new EventTypeFilter(SourceLevels.All) });

            Trace.TraceInformation("Configured Windows Azure Diagnostics");
        }

        private static void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                e.Cancel = e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any(Settings.ShouldRecycleInstance);
            }
            else if (e.Changes.Any(change => change is RoleEnvironmentTopologyChange))
            {
                e.Cancel = false;
            }

            // Log the Changing Event
            foreach (var change in e.Changes)
            {
                Trace.Write(string.Format("RoleEnvironment Instant {0} - Changing Event: {1}", RoleEnvironment.CurrentRoleInstance.Id, change));
            }
        }

        private void RequestRoutingManager_StatusChange(object sender, RequestRoutingManagerEventArgs e)
        {
            Trace.TraceInformation(e.StatusMessage);
        }
    }
}
